package cn.itcast.order.service.impl;

import cn.itcast.order.client.AccountClient;
import cn.itcast.order.client.StorageClient;
import cn.itcast.order.entity.Order;
import cn.itcast.order.mapper.OrderMapper;
import cn.itcast.order.service.OrderService;
import feign.FeignException;
import io.seata.core.context.RootContext;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.apache.skywalking.apm.toolkit.trace.Tag;
import org.apache.skywalking.apm.toolkit.trace.Tags;
import org.apache.skywalking.apm.toolkit.trace.Trace;
import org.springframework.stereotype.Service;

import java.util.concurrent.*;

/**
 * @author 虎哥
 */
@Slf4j
@Service
public class OrderServiceImpl implements OrderService {

    private final AccountClient accountClient;
    private final StorageClient storageClient;
    private final OrderMapper orderMapper;

    public OrderServiceImpl(AccountClient accountClient, StorageClient storageClient, OrderMapper orderMapper) {
        this.accountClient = accountClient;
        this.storageClient = storageClient;
        this.orderMapper = orderMapper;
    }

    // 使用自定义线程池，确保上下文传递
    private final ExecutorService executor = new ThreadPoolExecutor(
            5, 10, 60L, TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(),
            new ThreadFactory() {
                @Override
                public Thread newThread(Runnable r) {
                    return new Thread(r);
                }
            },
            new ThreadPoolExecutor.CallerRunsPolicy()
    );

    @Override
    @GlobalTransactional
    @Trace
    @Tags({@Tag(key = "param", value = "arg[0]"),
            @Tag(key = "create", value = "returnedObj")})
    public Long create(Order order) {
        // 创建订单
        orderMapper.insert(order);
        String xid = RootContext.getXID();
        try {
            //异步执行获取不到Xid

            // 3. 异步扣减库存 - 手动传递XID
            CompletableFuture<Void> amountFuture = CompletableFuture.runAsync(() -> {
                // 手动设置XID到当前异步线程
                RootContext.bind(xid);
                try {
                    accountClient.deduct(order.getUserId(), order.getMoney());
                } finally {
                    // 清除上下文，避免线程复用导致的问题
                    RootContext.unbind();
                }
            }, executor);

            // 4. 异步扣减余额 - 手动传递XID
            CompletableFuture<Void> stockFuture = CompletableFuture.runAsync(() -> {
                RootContext.bind(xid);
                try {
                    storageClient.deduct(order.getCommodityCode(), order.getCount());
                } finally {
                    RootContext.unbind();
                }
            }, executor);

            CompletableFuture.allOf(amountFuture, stockFuture).join();
            // 扣用户余额
            //accountClient.deduct(order.getUserId(), order.getMoney());
            // 扣库存
            //storageClient.deduct(order.getCommodityCode(), order.getCount());

        } catch (FeignException e) {
            log.error("下单失败，原因:{}", e.contentUTF8(), e);
            throw new RuntimeException(e.contentUTF8(), e);
        }
        return order.getId();
    }
}
